package appTempl

import (
	"fmt"
	"strconv"
	"time"

	"github.com/astaxie/beego/orm"
	"github.com/golang/glog"

	"eccgateway/pkg/api/dataselect"
	"eccgateway/pkg/db/auth"
	"eccgateway/pkg/db/util"
)

type Templ struct {
	Uuid          string    `json:"uuid" orm:"column(id);unique;pk"`
	Name          string    `json:"name" orm:"column(name)"`
	UserId        string    `json:"user_id" orm:"column(user_id)"`
	Arch          string    `json:"arch" orm:"column(arch)"`
	Creator       string    `json:"creator" orm:"column(creator)"`
	Template      string    `json:"template" orm:"column(template);type(text)"`
	Version       string    `json:"version" orm:"column(version)"`
	Privacy       string    `json:"privacy" orm:"column(privacy)"`
	Auditor       string    `json:"auditor" orm:"column(auditor)"`
	AuditResult   string    `json:"auditResult" orm:"column(auditResult)"`
	AuditTime     time.Time `json:"auditTime" orm:"column(auditTime)"`
	CreateTime    time.Time `json:"createTime" orm:"column(createTime)"`
	Status        int       `json:"status" orm:"column(status)"`
	Desc          string    `json:"desc" orm:"column(desc);type(text)"`
	Modifier      string    `json:"modifier" orm:"column(modifier)"`
	ModifyTime    time.Time `json:"modify_time" orm:"column(modify_time)"`
	Log           string    `json:"log" orm:"column(log)"`
	ImageUrl      string    `json:"image_url" orm:"column(image_url)"`
	Industry      string    `json:"industry" orm:"column(industry)"`
	Type          string    `json:"type" orm:"column(type)"`
	Title         string    `json:"title" orm:"column(title)"`
	Kind          string    `json:"kind" orm:"column(kind)"`
	DownloadCount int       `json:"downloadCount" orm:"column(downloadCount)"`
	StarCount     int       `json:"starCount" orm:"column(starCount)"`
}

var existKeyInTempl = map[string]bool{
	"id":            true,
	"name":          true,
	"user_id":       true,
	"arch":          true,
	"creator":       true,
	"version":       true,
	"privacy":       true,
	"auditor":       true,
	"auditResult":   true,
	"auditTime":     true,
	"createTime":    true,
	"status":        true,
	"desc":          true,
	"modifier":      true,
	"modify_time":   true,
	"log":           true,
	"image_url":     true,
	"industry":      true,
	"type":          true,
	"title":         true,
	"kind":          true,
	"downLoadCount": true,
	"starCount":     true,
	// not allow filter by template
	//"template":         true,
}

type Log struct {
	ID          int       `json:"id" orm:"column(id);unique"`
	Version     string    `json:"version" orm:"column(version)"`
	TemplUuid   string    `json:"templ_uuid" orm:"column(templateUuid)"`
	Name        string    `json:"name" orm:"column(name)"`
	AuditResult string    `json:"auditResult" orm:"column(auditResult)"`
	Auditor     string    `json:"auditor" orm:"column(auditor)"`
	AuditTime   time.Time `json:"auditTime" orm:"column(auditTime)"`
	Desc        string    `json:"desc" orm:"column(desc);type(text)"`
}

func (t *Templ) TableName() string {
	return "templ"
}

func CreateAppTempl(o orm.Ormer, t Templ) (Templ, error) {
	templ, e := GetAppTemplByNameAndVersion(o, t.Name, t.Version)
	if e == nil && templ != (Templ{}) {
		return t, fmt.Errorf("duplicate template found")
	}
	_, err := o.Insert(&t)
	if err != nil {
		return t, err
	}
	return GetAppTemplByNameAndUserID(o, t.Name, t.Uuid)
}

func GetAppTemplByNameAndUserID(o orm.Ormer, name string, uuid string) (Templ, error) {
	temp := Templ{}
	err := o.QueryTable(Templ{}).Filter("name", name).Filter("id", uuid).One(&temp)
	return temp, err
}

func GetAppTemplByNameAndVersion(o orm.Ormer, name string, version string) (Templ, error) {
	templ := Templ{}
	err := o.QueryTable(Templ{}).Filter("name", name).Filter("version", version).One(&templ)
	return templ, err
}

func ListTemplByName(o orm.Ormer, name string) ([]Templ, error) {
	var tempList []Templ
	res := o.QueryTable(Templ{}).Filter("name", name)
	_, err := res.All(tempList)
	return tempList, err
}

func GetUserIdByTemplUuid(o orm.Ormer, templUuid string) (string, error) {
	templ := Templ{}
	var userId string
	err := o.QueryTable(Templ{}).Filter("uuid", templUuid).One(&templ)
	if err != nil {
		return userId, err
	}
	userId = templ.UserId
	return userId, err
}

func GetGroupIdByUseId(o orm.Ormer, useId string) (string, error) {
	user := auth.User{}
	var groupId string
	err := o.QueryTable(auth.User{}).Filter("uuid", useId).One(&user)
	if err != nil {
		return groupId, err
	}
	groupId = strconv.Itoa(user.Group.Id)
	return groupId, err
}

func ListTemplAll(o orm.Ormer, userIDs []string, query *dataselect.DataSelectQuery) ([]Templ, int64, error) {
	var allTempl []Templ
	origin := o.QueryTable(Templ{})
	origin, count, err := util.Search(origin, userIDs, query, existKeyInTempl)
	if err != nil {
		return allTempl, 0, nil
	}
	_, err = origin.All(&allTempl)
	return allTempl, count, err
}

func UpdateTemplDownLoad(o orm.Ormer, templUuid string) (Templ, error) {
	templ := Templ{}
	err := o.QueryTable(Templ{}).Filter("uuid", templUuid).One(&templ)
	if err != nil {
		glog.Errorf("cannot find template for uuid %s", templUuid)
		return templ, err
	}
	templ.DownloadCount = templ.DownloadCount + 1
	_, err = o.Update(&templ, "downloadCount")
	return templ, err
}

func IncreaseTemplStar(o orm.Ormer, templUuid string) (Templ, error) {
	templ := Templ{}
	err := o.QueryTable(Templ{}).Filter("uuid", templUuid).One(&templ)
	if err != nil {
		glog.Errorf("cannot find template for uuid %s", templUuid)
		return templ, err
	}
	templ.StarCount = templ.StarCount + 1
	_, err = o.Update(&templ, "starCount")
	return templ, err
}

func decreaseTemplStar(o orm.Ormer, templUuid string) (Templ, error) {
	templ := Templ{}
	err := o.QueryTable(Templ{}).Filter("uuid", templUuid).One(&templ)
	if err != nil {
		glog.Errorf("cannot find template for uuid %s", templUuid)
		return templ, err
	}
	templ.StarCount = templ.StarCount - 1
	_, err = o.Update(&templ, "starCount")
	if err != nil {
		glog.Errorf("cannot update template for uuid %s", templUuid)
		return templ, err
	}
	return templ, err
}

func SetTemplPublic(o orm.Ormer, templUuid string) (Templ, error) {
	templ := Templ{}
	err := o.QueryTable(Templ{}).Filter("uuid", templUuid).One(&templ)
	if err != nil {
		glog.Errorf("cannot find template for uuid %s", templUuid)
		return templ, err
	}
	templ.Status = 2
	_, err = o.Update(&templ, "status")
	return templ, err
}

func UpdateTempl(o orm.Ormer, templ Templ) error {
	_, e := o.Update(&templ)
	return e
}

func GetPubTempList(o orm.Ormer, query *dataselect.DataSelectQuery) ([]Templ, int64, error) {
	var pubTemplLIst []Templ
	origin := o.QueryTable(Templ{}).Filter("privacy", "1")
	origin, count, err := util.Search(origin, nil, query, existKeyInTempl)
	if err != nil {
		glog.Errorf("list template error %s", err.Error())
		return pubTemplLIst, 0, err
	}
	_, err = origin.All(&pubTemplLIst)
	if err != nil {
		glog.Errorf("list public template error %s", err.Error())
		return pubTemplLIst, 0, err
	}
	return pubTemplLIst, count, nil
}

func GetTemplByUuid(o orm.Ormer, uuid string) (Templ, error) {
	templ := Templ{}
	err := o.QueryTable(Templ{}).Filter("uuid", uuid).One(&templ)
	return templ, err
}

func DeleteTempl(o orm.Ormer, templ Templ) error {
	_, err := o.Delete(&templ)
	return err
}

func InsertLog(o orm.Ormer, log Log) error {
	_, err := o.Insert(&log)
	return err
}

func GetLogs(o orm.Ormer, templName string, version string) ([]Log, error) {
	logs := []Log{}
	_, e := o.QueryTable(Log{}).Filter("name", templName).Filter("version", version).All(&logs)
	return logs, e
}

func CheckUserGroupIsEqual(user1Id, user2Id string) (bool, error) {
	userGroupId1, err := GetGroupIdByUseId(orm.NewOrm(), user1Id)
	if err != nil {
		glog.Errorf("cannot find user Group for uuid: %s", user1Id)
		return false, err
	}
	userGroupId2, err := GetGroupIdByUseId(orm.NewOrm(), user2Id)
	if err != nil {
		glog.Errorf("cannot find user Group for uuid: %s", user2Id)
		return false, err
	}
	return userGroupId1 == userGroupId2, nil
}
